/**
  ******************************************************************************
  * @file    data_check.c
  * @author  ashuai0110
  * @version V2.4
  * @date    2024-09-10
  * @brief   数据校验方法集合
  *
  ******************************************************************************
  * @attention
  *
  * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
  * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
  *
  * Change Logs:
  * Date          Author        Notes
  * 2023-10-17    ashuai0110    完成基本内容
  * 2023-12-29    ashuai0110    新增sum,xor,crc校验
  * 2024-01-04    ashuai0110    修复crc校验中的问题
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "data_check.h"

/**
 * @addtogroup modules
 * @{
 */

/**
 * @defgroup data_check data_check
 * @{
 */

/* 私有宏定义-----------------------------------------------------------------*/

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/
/**
 * @defgroup data_check_global_functions data check global functions
 * @{
 */

/**
  * @brief  累加和校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint8_t check_sum(uint8_t *data, uint16_t len)
{
    uint8_t sum = 0;

    while(len--)
    {
        sum += *data;
        data++;
    }

    return sum;
}

/**
  * @brief  异或和校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint8_t check_xor(uint8_t *data, uint16_t len)
{
    uint8_t xor = 0;

    while(len--)
    {
        xor ^= *data;
        data++;
    }

    return xor;
}

/**
  * @brief  LRC校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint8_t check_lrc(uint8_t *data, uint16_t len)
{
    uint8_t lrc = 0;
    
    while(len--)
    {
        lrc += *data;
        data++;
    }
    lrc = (~lrc) + 1;
    
    return lrc;
}

/**
  * @brief  CRC4-ITU校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint8_t check_crc4_itu(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint8_t crc = 0;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x01)
            {
                crc = (crc >> 1) ^ 0x0C;
            }
            else
            {
                crc >>= 1;
            }
        }
    }

    return crc;
}

/**
  * @brief  CRC5-EPC校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint8_t check_crc5_epc(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint8_t crc = 0x48;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; cnt++)
        {
            if(crc & 0x80)
            {
                crc = (crc << 1) ^ 0x48;
            }
            else
            {
                crc <<= 1;
            }
        }
    }
    crc >>= 3;

    return crc;
}

/**
  * @brief  CRC5-ITU校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint8_t check_crc5_itu(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint8_t crc = 0;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x01)
            {
                crc = (crc >> 1) ^ 0x15;
            }
            else
            {
                crc >>= 1;
            }
        }
    }

    return crc;
}

/**
  * @brief  CRC5-USB校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint8_t check_crc5_usb(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint8_t crc = 0x1F;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x01)
            {
                crc = (crc >> 1) ^ 0x14;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    crc ^= 0x1F;

    return crc;
}

/**
  * @brief  CRC6-ITU校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint8_t check_crc6_itu(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint8_t crc = 0;
    
    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x01)
            {
                crc = (crc >> 1) ^ 0x30;
            }
            else
            {
                crc >>= 1;
            }
        }
    }

    return crc;
}

/**
  * @brief  CRC7-MMC校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint8_t check_crc7_mmc(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint8_t crc = 0;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; cnt++)
        {
            if(crc & 0x80)
            {
                crc = (crc << 1) ^ 0x12;
            }
            else
            {
                crc <<= 1;
            }
        }
    }
    crc >>= 1;

    return crc;
}

/**
  * @brief  CRC8校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint8_t check_crc8(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint8_t crc = 0;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; cnt++)
        {
            if(crc & 0x80)
            {
                crc = (crc << 1) ^ 0x07;
            }
            else
            {
                crc <<= 1;
            }
        }
    }

    return crc;
}

/**
  * @brief  CRC8-ITU校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint8_t check_crc8_itu(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint8_t crc = 0;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; cnt++)
        {
            if(crc & 0x80)
            {
                crc = (crc << 1) ^ 0x07;
            }
            else
            {
                crc <<= 1;
            }
        }
    }
    crc ^= 0x55;

    return crc;
}

/**
  * @brief  CRC8-ROHC校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint8_t check_crc8_rohc(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint8_t crc = 0xFF;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x01)
            {
                crc = (crc >> 1) ^ 0xE0;
            }
            else
            {
                crc >>= 1;
            }
        }
    }

    return crc;
}

/**
  * @brief  CRC8-MAXIM校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint8_t check_crc8_maxim(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint8_t crc = 0;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; cnt++)
        {
            if(crc & 0x01)
            {
                crc = (crc >> 1) ^ 0x8C;
            }
            else
            {
                crc >>= 1;
            }
        }
    }

    return crc;
}

/**
  * @brief  CRC16-IBM校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint16_t check_crc16_ibm(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint16_t crc = 0;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x01)
            {
                crc = (crc >> 1) ^ 0xA001;
            }
            else
            {
                crc >>= 1;
            }
        }
    }

    return crc;
}

/**
  * @brief  CRC16-MAXIM校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint16_t check_crc16_maxim(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint16_t crc = 0;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x01)
            {
                crc = (crc >> 1) ^ 0xA001;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    crc = ~crc;

    return crc;
}

/**
  * @brief  CRC16-USB校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint16_t check_crc16_usb(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint16_t crc = 0xFFFF;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x01)
            {
                crc = (crc >> 1) ^ 0xA001;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    crc = ~crc;

    return crc;
}

/**
  * @brief  CRC16-MODBUS校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint16_t check_crc16_modbus(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint16_t crc = 0xFFFF;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x01)
            {
                crc = (crc >> 1) ^ 0xA001;
            }
            else
            {
                crc >>= 1;
            }
        }
    }

    return crc;
}

/**
  * @brief  CRC16-CCITT校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint16_t check_crc16_ccitt(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint16_t crc = 0;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x01)
            {
                crc = (crc >> 1) ^ 0x8408;
            }
            else
            {
                crc >>= 1;
            }
        }
    }

    return crc;
}

/**
  * @brief  CRC16-CCITT-FALSE校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint16_t check_crc16_ccitt_false(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint16_t crc = 0xFFFF;

    while(len--)
    {
        crc ^= (uint16_t)(*data) << 8;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x8000)
            {
                crc = (crc << 1) ^ 0x1021;
            }
            else
            {
                crc <<= 1;
            }
        }
    }

    return crc;
}

/**
  * @brief  CRC16-X25校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint16_t check_crc16_x25(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint16_t crc = 0xFFFF;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if (crc & 0x01)
            {
                crc = (crc >> 1) ^ 0x8408;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    crc = ~crc;

    return crc;
}

/**
  * @brief  CRC16-XMODEM校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint16_t check_crc16_xmodem(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint16_t crc = 0;

    while(len--)
    {
        crc ^= (uint16_t)(*data) << 8;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x8000)
            {
                crc = (crc << 1) ^ 0x1021;
            }
            else
            {
                crc <<= 1;
            }
        }
    }

    return crc;
}

/**
  * @brief  CRC16-DNP校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint16_t check_crc16_dnp(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint16_t crc = 0;

    while(len--)
    {
        crc ^= *data;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x01)
            {
                crc = (crc >> 1) ^ 0xA6BC;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    crc = ~crc;

    return crc;
}

/**
  * @brief  CRC32校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint32_t check_crc32(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint32_t crc = 0xFFFFFFFF;

    while(len--)
    {
        crc ^= *data++;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x01)
            {
                crc = (crc >> 1) ^ 0xEDB88320;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    crc = ~crc;

    return crc;
}

/**
  * @brief  CRC32-MPEG-2校验
  *
  * @param  data : 校验数据
  *
  * @param  len  : 校验数据长度
  *
  * @retval 返回校验结果
  */
uint32_t check_crc32_mpeg_2(uint8_t *data, uint16_t len)
{
    uint8_t cnt;
    uint32_t crc = 0xFFFFFFFF;

    while(len--)
    {
        crc ^= (uint32_t)(*data) << 24;
        data++;
        for(cnt = 0; cnt < 8; ++cnt)
        {
            if(crc & 0x80000000)
            {
                crc = (crc << 1) ^ 0x04C11DB7;
            }
            else
            {
                crc <<= 1;
            }
        }
    }

    return crc;
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
